package com.xq.controller;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;

public class XQHttpClinet {

	public final static String METHOD_GET = "get";
	public final static String METHOD_POST = "post";

	private final int connectionTimeoutMillis = 20000;
	private final int socketTimeoutMillis = 20000;


	public Result<String> execute(Request request) {
		return execute(request, new StringResponseParser());
	}
	
	public <T> Result<T> execute(Request request, ResponseParser<T> parser) {

		Result<T> result = new Result<T>();
		HttpClient httpClient = new DefaultHttpClient();
		/*((DefaultHttpClient) httpClient).getCredentialsProvider()
				.setCredentials(new AuthScope("192.168.1.103", 8888),
						new UsernamePasswordCredentials("", ""));
		HttpHost proxy = new HttpHost("192.168.1.103", 8888);
		httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,
				proxy);*/
		HttpParams httpParams = httpClient.getParams();
		HttpConnectionParams.setConnectionTimeout(httpParams,
				connectionTimeoutMillis);
		HttpConnectionParams.setSoTimeout(httpParams, socketTimeoutMillis);
		HttpRequestBase httpRequest = null;
		if (METHOD_GET.equalsIgnoreCase(request.getMethod())) {
			httpRequest = getHttpGetRequest(request.getUrl(),
					request.getParas());
		} else {
			if (request.getFileEntities().isEmpty()
					&& request.getStringEntities().isEmpty()) {
				httpRequest = getHttpPostRequest(request.getUrl(),
						request.getParas());
			} else {
				httpRequest = getHttpPostRequest(request.getUrl(),
						request.getStringEntities(), request.getFileEntities());
			}
		}
		// set headers
		if (!request.getHeaders().isEmpty()) {
			for (String headName : request.getHeaders().keySet()) {
				httpRequest.setHeader(headName,
						request.getHeaders().get(headName));
			}
		}

		try {
			HttpContext httpContext = new BasicHttpContext();
			CookieStore cookieStore = new BasicCookieStore();
			httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
			HttpResponse response;
			response = httpClient.execute(httpRequest, httpContext);
			int statusCode = response.getStatusLine().getStatusCode();
			result.setHttpStatus(statusCode);
			try {

				result.setData(parser.parse(response.getEntity().getContent()));
			} catch (Exception e) {
				result.setResponseParserException(e);
			}
		} catch (Exception e) {
			result.setHttpException(e);
		} finally {
			httpClient.getConnectionManager().shutdown();
		}

		return result;
	}
	
	public void cancelRequest()
	{
		//TODO:
	}

	private HttpRequestBase getHttpGetRequest(String url,
			Map<String, String> paramObject) {
		List<NameValuePair> params = generateNameValuePairList(paramObject);
		if (!params.isEmpty()) {
			String paramString = URLEncodedUtils.format(params, "utf-8");
			if (url.contains("?")) {
				url += "&" + paramString;
			} else {
				url += "?" + paramString;
			}
		}
		HttpGet get = new HttpGet(url);
		return get;
	}

	@SuppressWarnings("unused")
	private HttpRequestBase getHttpPostRequest(String url,
			Map<String, String> paramObject) {
		HttpPost post = new HttpPost(url);
		try {
			post.setEntity(new UrlEncodedFormEntity(
					generateNameValuePairList(paramObject), Charset.forName("UTF-8")));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return post;
	}

	private HttpRequestBase getHttpPostRequest(String url,
			Map<String, String> stringEntities, Map<String, List> fileEntities) {
		HttpPost post = new HttpPost(url);
		MultipartEntity entity = new MultipartEntity();
		if (stringEntities != null && !stringEntities.isEmpty()) {
			for (String key : stringEntities.keySet()) {
				try {
					entity.addPart(key, new StringBody(stringEntities.get(key),
							Charset.forName("UTF-8")));
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
			}
		}

		if (fileEntities != null && !fileEntities.isEmpty()) {
			for (String key : fileEntities.keySet()) {
				List fileInfo = (List) fileEntities.get(key);
				// entity.addPart(key, new FileBody((File) fileInfo.get(0),
				// (String) fileInfo.get(1)));
				entity.addPart(
						key,
						new FileBody((File) fileInfo.get(0), ((File) fileInfo
								.get(0)).getName(), (String) fileInfo.get(1),
								""));
			}
		}
		post.setEntity(entity);
		return post;
	}

	private List<NameValuePair> generateNameValuePairList(
			Map<String, String> parameters) {
		List<NameValuePair> params = new ArrayList<NameValuePair>();
		if (parameters != null && !parameters.isEmpty()) {
			for (String key : parameters.keySet()) {
				params.add(new BasicNameValuePair(key, parameters.get(key)));
			}
		}
		return params;
	}

	public static class Result<T> {
		
		private int httpStatus;

		private Exception responseParserException;

		private Exception httpException;

		private T data;

		public int getHttpStatus() {
			return httpStatus;
		}

		public void setHttpStatus(int httpStatus) {
			this.httpStatus = httpStatus;
		}

		public T getData() {
			return data;
		}

		public void setData(T data) {
			this.data = data;
		}

		public Exception getResponseParserException() {
			return responseParserException;
		}

		public void setResponseParserException(Exception responseParserException) {
			this.responseParserException = responseParserException;
		}

		public Exception getHttpException() {
			return httpException;
		}

		public void setHttpException(Exception httpException) {
			this.httpException = httpException;
		}

	}

	public static interface ResponseParser<T> {
		T parse(InputStream in) throws Exception;
	}

	public static class StringResponseParser implements ResponseParser<String> {

		@Override
		public String parse(InputStream in) throws Exception {
			StringBuffer stringBuffer = new StringBuffer();
			BufferedReader bufferReader = new BufferedReader(
					new InputStreamReader(in));
			String line = null;
			while ((line = bufferReader.readLine()) != null) {
				stringBuffer.append(line + "\r\n");
			}
			String result = stringBuffer.toString();
			return result;
		}
	}

	public static class FileResponseParser implements ResponseParser<File> {

		@Override
		public File parse(InputStream in) throws Exception {
			File file = File
					.createTempFile(UUID.randomUUID().toString(), "tmp");
			OutputStream outputStream = new FileOutputStream(file);
			BufferedInputStream inputStream = new BufferedInputStream(in);
			int read = 0;
			byte[] bytes = new byte[1024];
			while ((read = inputStream.read(bytes)) != -1) {
				outputStream.write(bytes, 0, read);
			}
			outputStream.flush();
			outputStream.close();
			return file;
		}
	}

	public static class Request {

		private String method = METHOD_GET;
		private String url;
		private Map<String, String> headers = new HashMap<String, String>();
		private Map<String, String> paras = new HashMap<String, String>();
		private Map<String, String> stringEntities = new HashMap<String, String>();
		private Map<String, List> fileEntities = new HashMap<String, List>();

		public Request setMethod(String method) {
			this.method = method;
			return this;
		}

		public Request addFileEntity(String name, File file, String contentType) {
			List fileInfo = new ArrayList();
			fileInfo.add(file);
			fileInfo.add(contentType);
			fileEntities.put(name, fileInfo);
			return this;
		}

		public Request addStringEntity(String name, String value) {
			stringEntities.put(name, value);
			return this;
		}

		public Request addHeader(String name, String value) {
			headers.put(name, value);
			return this;
		}

		public Request addPara(String name, String value) {
			paras.put(name, value);
			return this;
		}

		public Map<String, String> getHeaders() {
			return headers;
		}

		public void setHeaders(Map<String, String> headers) {
			this.headers = headers;
		}

		public Map<String, String> getParas() {
			return paras;
		}

		public void setParas(Map<String, String> paras) {
			this.paras = paras;
		}

		public Map<String, String> getStringEntities() {
			return stringEntities;
		}

		public void setStringEntities(Map<String, String> stringEntities) {
			this.stringEntities = stringEntities;
		}

		public Map<String, List> getFileEntities() {
			return fileEntities;
		}

		public void setFileEntities(Map<String, List> fileEntities) {
			this.fileEntities = fileEntities;
		}

		public String getMethod() {
			return method;
		}

		public String getUrl() {
			return url;
		}

		public Request setUrl(String url) {
			this.url = url;
			return this;
		}

	}
	
	public static void main(String[] args) {
		//表单含有文件选项提交
		Request request = new Request()
				.setUrl("http://192.168.1.103:8081/user/register")
				.setMethod(METHOD_POST)
				.addStringEntity("phone", "15901902994")
				.addFileEntity("portrait",
						new File("/Users/dhe/Downloads/2014-05-17 203741.jpg"),
						"image/jpeg");

		XQHttpClinet client = new XQHttpClinet();
		/*try {
			Result<String> s = client.execute(request);
			printResult(s);
		} catch (Exception e) {
			e.printStackTrace();
		}*/

		//get 表单提交
		Request getRequest = new Request();
		getRequest.setMethod(METHOD_GET).setUrl("http://192.168.1.103:8081/user/login").addPara(
				"phone", "159").addPara("password", "1");
		try {
			//Result<String> s = client.execute(getRequest);
			//printResult(s);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		//post 表单提交
		Request postRequest = new Request();
		postRequest.setMethod(METHOD_POST).setUrl("http://192.168.1.103:8081/user/login").addPara(
				"phone", "159").addPara("password", "1");
		try {
			//Result<String> s = client.execute(postRequest);
			//printResult(s);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		//download file
		Request getImageRequest = new Request();
		getImageRequest.setMethod(METHOD_POST).setUrl("http://192.168.1.103:8081/upload/user1.jpg");
		try {
			Result<File> s = client.execute(getImageRequest, new FileResponseParser());
			printResult(s);
			File file = s.getData();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void printResult(Result s)
	{
			System.out.println(s.httpStatus);
			System.out.println(s.data);
			System.out.println(s.httpException);
			System.out.println(s.responseParserException);
	}
}
